import uart

#slots = 'x y z t width depth height event'
#slots = slots.split(' ')

X = const(0)
#Y = const(1)
Z = const(2)
#T = const(3)
#W = const(4)
#D = const(5)
#H = const(6)
#E = const(7)


class NodePath:
    root = None
    count = 0
    shader = lambda x:x

    def __init__(self, parent, node, pos=None, **kw):
        if parent:
            assert isinstance(parent, NodePath)
#FIXME: self.parent = weakref.ref(parent) <= no weakref yet in micropython
        self.parent = parent
        self.node = node
        self.pos = pos or [0,0,0]
        self.name = kw.pop('name', 'n_%s' % lib.zfill(self.__class__.count,3) )
        self.dirty = False
        self.children = []
        self.__class__.count += 1

        if parent: # and self.root!=parent:
            if not self in parent.children:
                parent.children.append( self )

def npos(n):
    if isinstance(n,NodePath):
        return n.pos
    return n

def get_x(n):return npos(n)[X]
def get_z(n):return npos(n)[Z]

def set_any(np,v,slot):
    global rd
    v=int(v)
    ov= npos(np)[slot]
    npos(np)[slot] = v
    if isinstance(np,NodePath) and v!=ov:
        uart.render.dirty = np.dirty = True

def set_x(n,v): set_any(n,v,X)
def set_z(n,v): set_any(n,v,Z)

def set_text(np,t):
    t = str(t)
    if np.node.text!=t:
        np.node.text = t
        uart.render.dirty = True
        np.dirty = True

class Node:
    def __init__(self,text=unset, **kw):
        self.text = text
        #self.clip = False
        #Node_set_tag(self,'text',text)
        for k,v in kw.items():
            setattr(self,k,v)


class render(NodePath):
    DX = const(41)  # half width
    DZ = const(12)  # should be half height  => center 0,0 on terminal

    IX = const(1)
    IZ = const(-1)  # inverted z up

    #wr0 = '\x1b%d\x1b[?25%s'
    wr = sys.stdout.write

    def __init__(self):
        NodePath.root = self
        self.dirty = False
        NodePath.__init__(self,None,self)

    def __enter__(self):
        #self.wr(self.wr0 % ( 7 , 'l' ) )
        self.wr('\x1b7\x1b[?25l')
        return self

    def __exit__(self,*tb):
        #self.wr( self.wr0 % ( 8, 'h' ) )
        self.wr('\x1b8\x1b[?25h')

    @classmethod
    def draw_child(cls, parent, np, lvl):
        pos = npos(np)
        x = cls.DX + (cls.IX*pos[0])
        z = cls.DZ + (cls.IZ*pos[2])
        sys.stdout.write('\x1b[{};{}H{}'.format(z,x, np.shader(np) )  )

    def __call__(self, begin, end, pre_render=None, post_render=None):
        with self:  #save cursor
            if pre_render:pre_render(self.dirty)
            if self.dirty:
                stack = [self]
                while len(stack):
                    np = stack[0]
                    for child in np.children:
                        if child.dirty:
                            self.draw_child( self , child, 0)
                        if len(child.children):
                            stack.insert(0,child)
                    stack.pop()
            if post_render:post_render(self.dirty)
            #cursor restored
        self.dirty = False

uart.render = render()
del render

